
package keul.planner.beans;

import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;

import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.inject.Named;
import keul.planner.entities.Line;
import keul.planner.entities.Station;
import keul.planner.tools.Tools;
import org.jgrapht.GraphPath;
import org.jgrapht.Graphs;
import org.jgrapht.alg.KShortestPaths;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;

/**
 * Diese Bean wird von calculateRoute.xhtml und home.xhtml genutzt.
 * Sie bietet Methoden, um eine Streckenberechnung durchzuführen
 * und darzusttellen.
 * @author kev
 */
@Stateless
@Named
public class RouteCalculationManager implements Serializable {

    @Inject
    DataManager dataManager;
    @Inject
    SessionManager sessionManager;
    
    private String startStationString;
    private String destinationStationString;
    private String hour;
    private String minute;
    private Station startStation;
    private Station destinationStation;
    
    @PostConstruct
    public void getTime() {
        minute = String.format("%02d", new Date(System.currentTimeMillis()).getMinutes());
        hour = String.format("%02d", new Date(System.currentTimeMillis()).getHours());
    }
    
    
    public String getDestinationStationString() {
        return destinationStationString;
    }

    public void setDestinationStationString(String destinationStationString) {
        this.destinationStationString = destinationStationString;
        this.destinationStation = dataManager.getStationByName(destinationStationString);
    }

    public String getStartStationString() {
        return startStationString;
    }

    public void setStartStationString(String startStationString) {
        this.startStationString = startStationString;
        this.startStation = dataManager.getStationByName(startStationString);
    }

    public String getHour() {
        return hour;
    }

    public void setHour(String hour) {
        this.hour = hour;
    }

    public String getMinute() {
        return minute;
    }

    public void setMinute(String minute) {
        this.minute = minute;
    }
    
    public Station getDestinationStation() {
        return destinationStation;
    }

    public void setDestinationStation(Station destinationStation) {
        this.destinationStation = destinationStation;
    }

    public Station getStartStation() {
        return startStation;
    }

    public void setStartStation(Station startStation) {
        this.startStation = startStation;
    }

    public String calculateRouteAction() {
        if (!startStation.equals(destinationStation))
            return "calculateRoute";
        return null;
    }
    
    /**
     * Gibt den günstigsten Pfad (als List<Station>) von einer Station 
     * zur anderen zurück.
     * @param start
     * @param target
     * @return 
     */
    public List<Station> getShortesPathAsList() {
        List<Station> stations = dataManager.getStationList();
        DefaultDirectedWeightedGraph net = dataManager.getNet();
        KShortestPaths<Station, Station> ksp = new KShortestPaths<Station, Station>(net, startStation, 1);
        GraphPath<Station, Station> path = ksp.getPaths(destinationStation).get(0);
        return Graphs.getPathVertexList(path);
    }

    /**
     * Hier wird von einer Station zur nächsten iteriert, und die Abfahrtszeiten
     * zu ermitteln und anzeigen zu können, und auch, welche Linie jede Verbindung
     * bedient und zeitlich am günstigsten liegt
     * @param stations
     * @return 
     */
    public List<String[]> rideFromStationToStation(List<Station> stations) {
        
        ArrayList<String[]> stringList = new ArrayList<String[]>();
        int currentMinutes = Integer.parseInt(hour) * 60 + Integer.parseInt(minute);
        int currentIndex = 0;
        List<Line> lines = dataManager.getLineList();

        while (currentIndex < stations.size()-1) {
            String[] strings = new String[4];
            Station currentStation = stations.get(currentIndex);
            Station desiredStation = stations.get(currentIndex + 1);
            strings[0] = currentStation + "->" + desiredStation;

            int counter = 0, bestLineIndex = -1;
            int[] minutes = new int[lines.size()];
            for (Line line : lines) {
                if (line.isLineDirectingTo(currentStation, desiredStation)) {
                    int departureTime = line.getNextDepartureTimeForCertainStationOnLine(currentStation, currentMinutes);
                    int nextStationArrivalTime = departureTime + (int)line.calculateMinutesToPreviousStation(desiredStation);
                    int bestNextStationArrivalTime = bestLineIndex==-1?-1:lines.get(bestLineIndex).getNextDepartureTimeForCertainStationOnLine(desiredStation, currentMinutes);
                    if ( ( bestLineIndex==-1 && nextStationArrivalTime>0 ) ||
                         ( bestNextStationArrivalTime>nextStationArrivalTime && nextStationArrivalTime>0 ) )
                        bestLineIndex = counter;
                }
                counter++;
            }

            if (bestLineIndex>=0) {
                int departureTime = lines.get(bestLineIndex).getNextDepartureTimeForCertainStationOnLine(currentStation, currentMinutes);
                int arrivalTime = departureTime + (int)lines.get(bestLineIndex).calculateMinutesToPreviousStation(desiredStation);
                currentMinutes = arrivalTime;
                strings[1] = lines.get(bestLineIndex).toString();
                strings[2] = "departure: " + getReadableTime(departureTime);
                strings[3] = "arrival: " + getReadableTime(arrivalTime);
            } else {
                strings[1] = "";
                strings[2] = "";
                strings[3] = "no direct connection available";
            }
            stringList.add(strings);
            currentIndex++;
        }
        
        OutputStream os;
        BufferedImage image;
        try {
            String specialFileName = sessionManager.getHash();
            os = new FileOutputStream("c:\\maps\\"+specialFileName+".jpg");
            image = Tools.drawMap(stations);
            ImageIO.write(image, "jpeg", os);
            os.close();
        } catch (Exception ex) {
            Logger.getLogger(RouteCalculationManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return stringList;       
    }
    
    /**
     * Diese Methode kürzt eine Menge aus Minuten
     * in Stunden; z.B. aus (int)1380 -> "23:00"
     * @param minutes
     * @return 
     */
    public String getReadableTime(int minutes) {
        int hour = minutes/60,
            min = minutes%60;
        return String.format("%02d:%02d", hour, min);
    }

    /**
     * Gibt eine Aufzählung bis zum übergebenem Maximum zurück;
     * {"00","01","02"...}
     * @param max
     * @return 
     */
    public String[] getNumbers(int max) {
        String[] strings = new String[max];
        for (int i = 0; i < max; i++) {
            strings[i]=String.format("%02d", i);
        }
        return strings;
    }
}
